//! 文件 Appender
//!
//! 将日志输出到文件，支持路径配置和目录自动创建。
//!
//! ## 主要类型
//!
//! - [`FileAppender`] - 文件输出 Appender
//!
//! ## 示例
//!
//! ```rust,ignore
//! use log4r::appender::{Appender, FileAppender};
//! use log4r::{Level, LogEvent};
//!
//! // 创建文件 Appender
//! let appender = FileAppender::new("logs/app.log")?;
//!
//! // 自定义配置
//! let appender = FileAppender::new("logs/app.log")?
//!     .with_level(Level::Debug);
//!
//! // 写入日志
//! let event = LogEvent::new(Level::Info, "my_app", "Hello, file!");
//! appender.write(&event)?;
//! appender.flush()?;
//! ```

use std::fs::{File, OpenOptions};
use std::io::{BufWriter, Write};
use std::path::{Path, PathBuf};
use std::sync::Mutex;

use crate::appender::Appender;
use crate::error::Log4rError;
use crate::event::LogEvent;
use crate::formatter::{Formatter, TextFormatter};
use crate::level::Level;

/// 文件日志输出器
///
/// 将日志写入指定文件，支持追加模式和级别过滤。
/// 线程安全，可在多线程环境中使用。
///
/// # 示例
///
/// ```rust,ignore
/// use log4r::appender::FileAppender;
/// use log4r::Level;
///
/// // 创建文件 Appender
/// let appender = FileAppender::new("logs/app.log")?;
///
/// // 自定义配置
/// let appender = FileAppender::new("logs/app.log")?
///     .with_level(Level::Debug);
/// ```
pub struct FileAppender {
    /// 日志文件路径
    path: PathBuf,
    /// 日志级别过滤（低于此级别的日志将被忽略）
    level: Level,
    /// 格式化器
    formatter: Box<dyn Formatter>,
    /// 带缓冲的文件写入器（Mutex 保护）
    writer: Mutex<BufWriter<File>>,
}

// 编译时断言：验证 FileAppender 实现 Send + Sync
const _: () = {
    const fn assert_send_sync<T: Send + Sync>() {}
    assert_send_sync::<FileAppender>();
};

impl FileAppender {
    /// 创建新的 FileAppender
    ///
    /// # Arguments
    /// * `path` - 日志文件路径（支持相对路径和绝对路径）
    ///
    /// # Returns
    /// * `Ok(FileAppender)` - 创建成功
    /// * `Err(Log4rError::IoError)` - 文件创建失败
    ///
    /// # 行为
    /// - 自动创建文件所在目录（如果不存在）
    /// - 以追加模式打开文件（不覆盖已有内容）
    /// - 默认级别过滤：Trace（不过滤任何日志）
    /// - 默认格式化器：TextFormatter
    pub fn new(path: impl AsRef<Path>) -> Result<Self, Log4rError> {
        let path = path.as_ref().to_path_buf();

        // 自动创建父目录
        if let Some(parent) = path.parent() {
            if !parent.as_os_str().is_empty() && !parent.exists() {
                std::fs::create_dir_all(parent).map_err(Log4rError::IoError)?;
            }
        }

        // 以追加模式打开文件
        let file = OpenOptions::new()
            .create(true)
            .append(true)
            .open(&path)
            .map_err(Log4rError::IoError)?;

        let writer = BufWriter::new(file);

        Ok(Self {
            path,
            level: Level::Trace,
            formatter: Box::new(TextFormatter::new()),
            writer: Mutex::new(writer),
        })
    }

    /// 设置日志级别过滤
    ///
    /// 低于此级别的日志将被忽略，不写入文件。
    pub fn with_level(mut self, level: Level) -> Self {
        self.level = level;
        self
    }

    /// 设置自定义格式化器
    pub fn with_formatter(mut self, formatter: Box<dyn Formatter>) -> Self {
        self.formatter = formatter;
        self
    }

    /// 获取文件路径
    pub fn path(&self) -> &Path {
        &self.path
    }

    /// 获取当前级别过滤设置
    pub fn level(&self) -> Level {
        self.level
    }
}

impl Appender for FileAppender {
    fn write(&self, event: &LogEvent) -> Result<(), Log4rError> {
        // 级别过滤：低于阈值的日志直接返回
        if event.level < self.level {
            return Ok(());
        }

        // 格式化日志
        let formatted = self.formatter.format(event);

        // 获取锁并写入
        let mut writer = self.writer.lock().map_err(|_| Log4rError::AppenderError {
            name: "FileAppender".to_string(),
            cause: "获取文件锁失败".to_string(),
        })?;

        // 写入格式化字符串 + 换行符
        writeln!(writer, "{}", formatted).map_err(Log4rError::IoError)?;

        Ok(())
    }

    fn flush(&self) -> Result<(), Log4rError> {
        let mut writer = self.writer.lock().map_err(|_| Log4rError::AppenderError {
            name: "FileAppender".to_string(),
            cause: "获取文件锁失败".to_string(),
        })?;

        writer.flush().map_err(Log4rError::IoError)
    }

    fn close(&self) -> Result<(), Log4rError> {
        // 先刷新缓冲区
        self.flush()?;
        // BufWriter 在 drop 时会自动关闭文件
        Ok(())
    }
}

#[cfg(test)]
#[allow(clippy::unwrap_used, clippy::expect_used)]
mod tests {
    use super::*;
    use tempfile::TempDir;

    // ========================================
    // AC-5.1.5: Send + Sync 编译时断言
    // ========================================

    /// UT-5.1-007: 编译时验证 FileAppender 实现 Send + Sync
    #[test]
    fn test_file_appender_is_send_sync() {
        fn assert_send_sync<T: Send + Sync>() {}
        assert_send_sync::<FileAppender>();
    }

    /// UT-5.1-007b: 验证 FileAppender 实现 Appender trait
    #[test]
    fn test_file_appender_implements_appender() {
        fn accept_appender(_: &dyn Appender) {}
        fn accept_boxed_appender(_: Box<dyn Appender>) {}

        let temp_dir = TempDir::new().expect("创建临时目录失败");
        let log_path = temp_dir.path().join("trait_test.log");

        let appender = FileAppender::new(&log_path).expect("创建 FileAppender 失败");
        accept_appender(&appender);
        accept_boxed_appender(Box::new(
            FileAppender::new(temp_dir.path().join("boxed.log")).unwrap(),
        ));
    }

    // ========================================
    // AC-5.1.1: 基础文件写入测试
    // ========================================

    /// UT-5.1-001: 基础文件写入测试 - 验证日志被写入指定文件
    #[test]
    fn test_basic_file_write() {
        // GIVEN: FileAppender 和 LogEvent
        let temp_dir = TempDir::new().expect("创建临时目录失败");
        let log_path = temp_dir.path().join("basic.log");

        let appender = FileAppender::new(&log_path).expect("创建 FileAppender 失败");
        let event = LogEvent::new(Level::Info, "test_app", "Hello, file!");

        // WHEN: 写入日志并刷新
        appender.write(&event).expect("写入失败");
        appender.flush().expect("刷新失败");

        // THEN: 文件应包含日志内容
        let content = std::fs::read_to_string(&log_path).expect("读取文件失败");
        assert!(content.contains("Hello, file!"), "文件应包含消息");
        assert!(content.contains("[INFO ]"), "文件应包含级别");
        assert!(content.contains("test_app"), "文件应包含 target");
    }

    /// UT-5.1-008: 文件不存在时自动创建测试
    #[test]
    fn test_file_auto_create() {
        // GIVEN: 不存在的文件路径
        let temp_dir = TempDir::new().expect("创建临时目录失败");
        let log_path = temp_dir.path().join("auto_create.log");
        assert!(!log_path.exists(), "文件不应存在");

        // WHEN: 创建 FileAppender
        let appender = FileAppender::new(&log_path).expect("创建 FileAppender 失败");
        let event = LogEvent::new(Level::Info, "test", "message");
        appender.write(&event).expect("写入失败");
        appender.flush().expect("刷新失败");

        // THEN: 文件应被创建
        assert!(log_path.exists(), "文件应被创建");
    }

    // ========================================
    // AC-5.1.2: 格式化输出验证
    // ========================================

    /// UT-5.1-002: 格式化输出验证 - 验证使用 TextFormatter 格式化
    #[test]
    fn test_formatted_output() {
        // GIVEN: FileAppender 和 LogEvent
        let temp_dir = TempDir::new().expect("创建临时目录失败");
        let log_path = temp_dir.path().join("formatted.log");

        let appender = FileAppender::new(&log_path).expect("创建 FileAppender 失败");
        let event = LogEvent::new(Level::Warn, "my_app::module", "警告消息");

        // WHEN: 写入日志
        appender.write(&event).expect("写入失败");
        appender.flush().expect("刷新失败");

        // THEN: 输出应符合 TextFormatter 格式
        let content = std::fs::read_to_string(&log_path).expect("读取文件失败");
        // 格式: {time} [{level}] {target}: {message}
        assert!(content.contains("[WARN ]"), "应包含级别");
        assert!(content.contains("my_app::module:"), "应包含 target");
        assert!(content.contains("警告消息"), "应包含消息");
    }

    /// UT-5.1-009: with_formatter() builder 方法测试
    #[test]
    fn test_with_formatter() {
        // GIVEN: FileAppender 使用自定义格式化器
        let temp_dir = TempDir::new().expect("创建临时目录失败");
        let log_path = temp_dir.path().join("custom_formatter.log");

        let appender = FileAppender::new(&log_path)
            .expect("创建 FileAppender 失败")
            .with_formatter(Box::new(TextFormatter::new()));

        let event = LogEvent::new(Level::Debug, "test", "debug message");

        // WHEN: 写入日志
        appender.write(&event).expect("写入失败");
        appender.flush().expect("刷新失败");

        // THEN: 应成功写入
        let content = std::fs::read_to_string(&log_path).expect("读取文件失败");
        assert!(content.contains("debug message"));
    }

    // ========================================
    // AC-5.1.3: 多条日志换行验证
    // ========================================

    /// UT-5.1-003: 多条日志换行验证 - 验证每条日志后有换行符
    #[test]
    fn test_multiple_logs_newline() {
        // GIVEN: FileAppender
        let temp_dir = TempDir::new().expect("创建临时目录失败");
        let log_path = temp_dir.path().join("newline.log");

        let appender = FileAppender::new(&log_path).expect("创建 FileAppender 失败");

        // WHEN: 写入多条日志
        for i in 0..5 {
            let event = LogEvent::new(Level::Info, "test", format!("消息 {}", i));
            appender.write(&event).expect("写入失败");
        }
        appender.flush().expect("刷新失败");

        // THEN: 每条日志应在单独一行
        let content = std::fs::read_to_string(&log_path).expect("读取文件失败");
        let lines: Vec<&str> = content.lines().collect();
        assert_eq!(lines.len(), 5, "应有 5 行日志");

        for (i, line) in lines.iter().enumerate() {
            assert!(
                line.contains(&format!("消息 {}", i)),
                "第 {} 行应包含对应消息",
                i
            );
        }
    }

    // ========================================
    // AC-5.1.4: 多线程并发写入测试
    // ========================================

    /// UT-5.1-004: 多线程并发写入测试 - 验证线程安全
    #[test]
    fn test_concurrent_writes() {
        use std::sync::Arc;
        use std::thread;

        // GIVEN: 共享的 FileAppender
        let temp_dir = TempDir::new().expect("创建临时目录失败");
        let log_path = temp_dir.path().join("concurrent.log");

        let appender = Arc::new(FileAppender::new(&log_path).expect("创建 FileAppender 失败"));
        let mut handles = vec![];

        // WHEN: 多线程并发写入
        for i in 0..4 {
            let appender_clone = Arc::clone(&appender);
            let handle = thread::spawn(move || {
                for j in 0..25 {
                    let event = LogEvent::new(
                        Level::Info,
                        "concurrent_test",
                        format!("Thread {} - Message {}", i, j),
                    );
                    appender_clone.write(&event).expect("写入失败");
                }
            });
            handles.push(handle);
        }

        // 等待所有线程完成
        for handle in handles {
            handle.join().expect("线程 join 失败");
        }
        appender.flush().expect("刷新失败");

        // THEN: 所有日志应被写入（共 100 条）
        let content = std::fs::read_to_string(&log_path).expect("读取文件失败");
        let lines: Vec<&str> = content.lines().collect();
        assert_eq!(lines.len(), 100, "应有 100 条日志");
    }

    // ========================================
    // AC-5.1.1: flush 和 close 方法测试
    // ========================================

    /// UT-5.1-005: flush 方法测试 - 验证缓冲区刷新
    #[test]
    fn test_flush() {
        // GIVEN: FileAppender
        let temp_dir = TempDir::new().expect("创建临时目录失败");
        let log_path = temp_dir.path().join("flush.log");

        let appender = FileAppender::new(&log_path).expect("创建 FileAppender 失败");
        let event = LogEvent::new(Level::Info, "test", "flush test");

        // WHEN: 写入并刷新
        appender.write(&event).expect("写入失败");
        let result = appender.flush();

        // THEN: flush 应成功
        assert!(result.is_ok());

        // 验证数据已写入文件
        let content = std::fs::read_to_string(&log_path).expect("读取文件失败");
        assert!(content.contains("flush test"));
    }

    /// UT-5.1-006: close 方法测试 - 验证关闭行为
    #[test]
    fn test_close() {
        // GIVEN: FileAppender
        let temp_dir = TempDir::new().expect("创建临时目录失败");
        let log_path = temp_dir.path().join("close.log");

        let appender = FileAppender::new(&log_path).expect("创建 FileAppender 失败");
        let event = LogEvent::new(Level::Info, "test", "close test");

        // WHEN: 写入并关闭
        appender.write(&event).expect("写入失败");
        let result = appender.close();

        // THEN: close 应成功
        assert!(result.is_ok());

        // 验证数据已写入文件
        let content = std::fs::read_to_string(&log_path).expect("读取文件失败");
        assert!(content.contains("close test"));
    }

    // ========================================
    // AC-5.1.1: path() getter 方法测试
    // ========================================

    /// UT-5.1-010: path() getter 方法测试
    #[test]
    fn test_path_getter() {
        // GIVEN: FileAppender
        let temp_dir = TempDir::new().expect("创建临时目录失败");
        let log_path = temp_dir.path().join("path_test.log");

        let appender = FileAppender::new(&log_path).expect("创建 FileAppender 失败");

        // WHEN: 获取路径
        let path = appender.path();

        // THEN: 应返回正确的路径
        assert_eq!(path, log_path.as_path());
    }

    // ========================================
    // 目录自动创建测试
    // ========================================

    /// UT-5.3-001: 目录自动创建测试
    #[test]
    fn test_directory_auto_create() {
        // GIVEN: 不存在的目录路径
        let temp_dir = TempDir::new().expect("创建临时目录失败");
        let nested_path = temp_dir.path().join("subdir").join("app.log");
        assert!(!nested_path.parent().unwrap().exists(), "目录不应存在");

        // WHEN: 创建 FileAppender
        let appender = FileAppender::new(&nested_path).expect("创建 FileAppender 失败");
        let event = LogEvent::new(Level::Info, "test", "message");
        appender.write(&event).expect("写入失败");
        appender.flush().expect("刷新失败");

        // THEN: 目录和文件应被创建
        assert!(nested_path.parent().unwrap().exists(), "目录应被创建");
        assert!(nested_path.exists(), "文件应被创建");
    }

    /// UT-5.3-002: 多级目录创建测试
    #[test]
    fn test_multi_level_directory_create() {
        // GIVEN: 多级不存在的目录路径
        let temp_dir = TempDir::new().expect("创建临时目录失败");
        let deep_path = temp_dir
            .path()
            .join("a")
            .join("b")
            .join("c")
            .join("app.log");

        // WHEN: 创建 FileAppender
        let appender = FileAppender::new(&deep_path).expect("创建 FileAppender 失败");
        let event = LogEvent::new(Level::Info, "test", "deep message");
        appender.write(&event).expect("写入失败");
        appender.flush().expect("刷新失败");

        // THEN: 所有目录和文件应被创建
        assert!(deep_path.exists(), "文件应被创建");
        let content = std::fs::read_to_string(&deep_path).expect("读取文件失败");
        assert!(content.contains("deep message"));
    }

    /// UT-5.3-003: 空父目录路径测试 - 验证无父目录的文件名
    #[test]
    fn test_empty_parent_path() {
        // GIVEN: 临时目录中的简单文件名（无子目录）
        let temp_dir = TempDir::new().expect("创建临时目录失败");
        let simple_path = temp_dir.path().join("app.log");

        // WHEN: 创建 FileAppender
        let appender = FileAppender::new(&simple_path).expect("创建 FileAppender 失败");
        let event = LogEvent::new(Level::Info, "test", "empty parent test");
        appender.write(&event).expect("写入失败");
        appender.flush().expect("刷新失败");

        // THEN: 文件应被创建（无需创建目录）
        assert!(simple_path.exists(), "文件应被创建");
        let content = std::fs::read_to_string(&simple_path).expect("读取文件失败");
        assert!(content.contains("empty parent test"));
    }

    /// UT-5.3-004: 已存在目录测试 - 验证目录已存在时不报错
    #[test]
    fn test_existing_directory() {
        // GIVEN: 已存在的目录
        let temp_dir = TempDir::new().expect("创建临时目录失败");
        let existing_dir = temp_dir.path().join("existing_dir");
        std::fs::create_dir(&existing_dir).expect("创建目录失败");
        assert!(existing_dir.exists(), "目录应已存在");

        let log_path = existing_dir.join("app.log");

        // WHEN: 创建 FileAppender
        let appender = FileAppender::new(&log_path).expect("创建 FileAppender 失败");
        let event = LogEvent::new(Level::Info, "test", "existing dir test");
        appender.write(&event).expect("写入失败");
        appender.flush().expect("刷新失败");

        // THEN: 文件应被创建，无错误
        assert!(log_path.exists(), "文件应被创建");
        let content = std::fs::read_to_string(&log_path).expect("读取文件失败");
        assert!(content.contains("existing dir test"));
    }

    /// UT-5.3-005: 深层嵌套目录测试 - 验证 5+ 级目录创建
    #[test]
    fn test_deep_nested_directory() {
        // GIVEN: 6 级嵌套目录路径
        let temp_dir = TempDir::new().expect("创建临时目录失败");
        let deep_path = temp_dir
            .path()
            .join("level1")
            .join("level2")
            .join("level3")
            .join("level4")
            .join("level5")
            .join("level6")
            .join("deep.log");

        // WHEN: 创建 FileAppender
        let appender = FileAppender::new(&deep_path).expect("创建 FileAppender 失败");
        let event = LogEvent::new(Level::Info, "test", "deep nested test");
        appender.write(&event).expect("写入失败");
        appender.flush().expect("刷新失败");

        // THEN: 所有 6 级目录和文件应被创建
        assert!(deep_path.exists(), "文件应被创建");
        assert!(
            deep_path.parent().expect("应有父目录").exists(),
            "level6 目录应存在"
        );
        let content = std::fs::read_to_string(&deep_path).expect("读取文件失败");
        assert!(content.contains("deep nested test"));
    }

    /// UT-5.3-006: 目录创建失败测试 - 验证返回 Log4rError::IoError
    /// 使用包含非法字符的路径触发目录创建失败
    #[test]
    fn test_directory_creation_failure() {
        // GIVEN: 包含非法字符的路径
        // Windows: 路径中不能包含 < > : " | ? * 等字符
        // Unix: 路径中不能包含 NUL 字符
        #[cfg(windows)]
        let invalid_path = std::path::PathBuf::from("C:\\invalid<dir>name\\test.log");

        #[cfg(unix)]
        let invalid_path = std::path::PathBuf::from("/\0invalid/test.log");

        // WHEN: 尝试创建 FileAppender
        let result = FileAppender::new(&invalid_path);

        // THEN: 应返回 IoError
        assert!(result.is_err(), "应返回错误");
        match result {
            Err(Log4rError::IoError(io_err)) => {
                // 验证返回了 IoError，具体的 ErrorKind 因平台而异
                // Windows: InvalidFilename, Unix: InvalidInput 或其他
                // 确保错误信息不为空
                let err_msg = io_err.to_string();
                assert!(!err_msg.is_empty(), "IoError 应包含错误信息");
            }
            Err(e) => panic!("应返回 IoError，实际返回: {:?}", e),
            Ok(_) => panic!("不应成功创建"),
        }
    }

    // ========================================
    // 追加写入测试
    // ========================================

    /// UT-5.5-001: 追加写入测试 - 验证文件已存在时新日志追加到末尾 (AC-5.5.1, AC-5.5.2)
    #[test]
    fn test_append_mode() {
        // GIVEN: 已存在内容的文件
        let temp_dir = TempDir::new().expect("创建临时目录失败");
        let log_path = temp_dir.path().join("append.log");

        // 先写入一些内容
        std::fs::write(&log_path, "existing content\n").expect("写入初始内容失败");

        // WHEN: 创建 FileAppender 并写入新内容
        let appender = FileAppender::new(&log_path).expect("创建 FileAppender 失败");
        let event = LogEvent::new(Level::Info, "test", "new message");
        appender.write(&event).expect("写入失败");
        appender.flush().expect("刷新失败");

        // THEN: 原有内容应保留，新内容应追加
        let content = std::fs::read_to_string(&log_path).expect("读取文件失败");
        assert!(content.contains("existing content"), "原有内容应保留");
        assert!(content.contains("new message"), "新内容应追加");
    }

    /// UT-5.5-002: 多次追加写入测试 - 验证连续多次写入都追加到文件末尾 (AC-5.5.1)
    #[test]
    fn test_multiple_append_writes() {
        // GIVEN: 已存在内容的文件
        let temp_dir = TempDir::new().expect("创建临时目录失败");
        let log_path = temp_dir.path().join("multi_append.log");

        std::fs::write(&log_path, "initial line\n").expect("写入初始内容失败");

        // WHEN: 创建 FileAppender 并多次写入
        let appender = FileAppender::new(&log_path).expect("创建 FileAppender 失败");
        for i in 1..=5 {
            let event = LogEvent::new(Level::Info, "test", format!("message {}", i));
            appender.write(&event).expect("写入失败");
        }
        appender.flush().expect("刷新失败");

        // THEN: 所有内容应按顺序存在
        let content = std::fs::read_to_string(&log_path).expect("读取文件失败");
        assert!(content.contains("initial line"), "初始内容应保留");
        for i in 1..=5 {
            assert!(
                content.contains(&format!("message {}", i)),
                "消息 {} 应存在",
                i
            );
        }

        // 验证行数：1 行初始 + 5 行日志
        let lines: Vec<&str> = content.lines().collect();
        assert_eq!(lines.len(), 6, "应有 6 行内容");
    }

    /// UT-5.5-003: 应用重启模拟测试 - 验证关闭后重新打开文件继续追加 (AC-5.5.1, AC-5.5.2)
    #[test]
    fn test_append_after_reopen() {
        // GIVEN: 创建 FileAppender 并写入内容
        let temp_dir = TempDir::new().expect("创建临时目录失败");
        let log_path = temp_dir.path().join("reopen.log");

        // 第一次打开并写入
        {
            let appender = FileAppender::new(&log_path).expect("创建 FileAppender 失败");
            let event = LogEvent::new(Level::Info, "app", "first session message");
            appender.write(&event).expect("写入失败");
            appender.flush().expect("刷新失败");
            appender.close().expect("关闭失败");
        } // appender 在此处 drop

        // WHEN: 模拟应用重启 - 重新创建 FileAppender 并写入
        {
            let appender = FileAppender::new(&log_path).expect("重新创建 FileAppender 失败");
            let event = LogEvent::new(Level::Info, "app", "second session message");
            appender.write(&event).expect("写入失败");
            appender.flush().expect("刷新失败");
        }

        // THEN: 两次会话的内容都应存在
        let content = std::fs::read_to_string(&log_path).expect("读取文件失败");
        assert!(
            content.contains("first session message"),
            "第一次会话内容应保留"
        );
        assert!(
            content.contains("second session message"),
            "第二次会话内容应追加"
        );

        // 验证顺序：第一次在前，第二次在后
        let first_pos = content.find("first session").expect("找不到第一次会话");
        let second_pos = content.find("second session").expect("找不到第二次会话");
        assert!(first_pos < second_pos, "第一次会话应在第二次之前");
    }

    /// UT-5.5-004: 大文件追加测试 - 验证对已有大量内容的文件追加 (AC-5.5.1, AC-5.5.2)
    #[test]
    fn test_append_to_large_file() {
        // GIVEN: 包含大量内容的文件
        let temp_dir = TempDir::new().expect("创建临时目录失败");
        let log_path = temp_dir.path().join("large.log");

        // 创建包含 1000 行的文件
        let mut initial_content = String::new();
        for i in 0..1000 {
            initial_content.push_str(&format!("existing line {}\n", i));
        }
        std::fs::write(&log_path, &initial_content).expect("写入初始内容失败");

        let initial_size = std::fs::metadata(&log_path).expect("获取元数据失败").len();

        // WHEN: 追加新日志
        let appender = FileAppender::new(&log_path).expect("创建 FileAppender 失败");
        let event = LogEvent::new(Level::Info, "test", "new appended message");
        appender.write(&event).expect("写入失败");
        appender.flush().expect("刷新失败");

        // THEN: 文件大小应增加，原有内容保留
        let final_size = std::fs::metadata(&log_path).expect("获取元数据失败").len();
        assert!(final_size > initial_size, "文件大小应增加");

        let content = std::fs::read_to_string(&log_path).expect("读取文件失败");
        assert!(content.contains("existing line 0"), "第一行应保留");
        assert!(content.contains("existing line 999"), "最后一行应保留");
        assert!(content.contains("new appended message"), "新消息应追加");
    }

    /// UT-5.5-005: 默认追加行为测试 - 验证无需配置即可获得追加行为 (AC-5.5.4)
    #[test]
    fn test_default_append_behavior() {
        // GIVEN: 已存在的文件
        let temp_dir = TempDir::new().expect("创建临时目录失败");
        let log_path = temp_dir.path().join("default_append.log");

        std::fs::write(&log_path, "pre-existing data\n").expect("写入初始内容失败");

        // WHEN: 使用默认配置创建 FileAppender（不调用任何配置方法）
        let appender = FileAppender::new(&log_path).expect("创建 FileAppender 失败");
        // 注意：没有调用任何 with_xxx 方法

        let event = LogEvent::new(Level::Info, "test", "default behavior test");
        appender.write(&event).expect("写入失败");
        appender.flush().expect("刷新失败");

        // THEN: 应自动使用追加模式，原有内容保留
        let content = std::fs::read_to_string(&log_path).expect("读取文件失败");
        assert!(
            content.contains("pre-existing data"),
            "原有内容应保留（默认追加）"
        );
        assert!(content.contains("default behavior test"), "新内容应追加");
    }

    // ========================================
    // 级别过滤测试（虽然本 Story 不要求，但已实现）
    // ========================================

    /// UT-5.4-001: 级别过滤 - 低于阈值被过滤
    #[test]
    fn test_level_filter_blocks_lower() {
        // GIVEN: 配置 WARN 级别的 FileAppender
        let temp_dir = TempDir::new().expect("创建临时目录失败");
        let log_path = temp_dir.path().join("filter.log");

        let appender = FileAppender::new(&log_path)
            .expect("创建 FileAppender 失败")
            .with_level(Level::Warn);

        // WHEN: 写入 INFO 级别日志（低于 WARN）
        let info_event = LogEvent::new(Level::Info, "test", "info message");
        appender.write(&info_event).expect("写入失败");
        appender.flush().expect("刷新失败");

        // THEN: 文件应为空（日志被过滤）
        let content = std::fs::read_to_string(&log_path).expect("读取文件失败");
        assert!(content.is_empty(), "INFO 日志应被过滤");
    }

    /// UT-5.4-002: 级别过滤 - 等于阈值通过
    #[test]
    fn test_level_filter_allows_equal() {
        // GIVEN: 配置 WARN 级别的 FileAppender
        let temp_dir = TempDir::new().expect("创建临时目录失败");
        let log_path = temp_dir.path().join("filter_equal.log");

        let appender = FileAppender::new(&log_path)
            .expect("创建 FileAppender 失败")
            .with_level(Level::Warn);

        // WHEN: 写入 WARN 级别日志
        let warn_event = LogEvent::new(Level::Warn, "test", "warn message");
        appender.write(&warn_event).expect("写入失败");
        appender.flush().expect("刷新失败");

        // THEN: 日志应被写入
        let content = std::fs::read_to_string(&log_path).expect("读取文件失败");
        assert!(content.contains("warn message"), "WARN 日志应通过");
    }

    /// UT-5.4-003: 级别过滤 - 高于阈值通过
    #[test]
    fn test_level_filter_allows_higher() {
        // GIVEN: 配置 WARN 级别的 FileAppender
        let temp_dir = TempDir::new().expect("创建临时目录失败");
        let log_path = temp_dir.path().join("filter_higher.log");

        let appender = FileAppender::new(&log_path)
            .expect("创建 FileAppender 失败")
            .with_level(Level::Warn);

        // WHEN: 写入 ERROR 级别日志
        let error_event = LogEvent::new(Level::Error, "test", "error message");
        appender.write(&error_event).expect("写入失败");
        appender.flush().expect("刷新失败");

        // THEN: 日志应被写入
        let content = std::fs::read_to_string(&log_path).expect("读取文件失败");
        assert!(content.contains("error message"), "ERROR 日志应通过");
    }

    /// UT-5.4-004: 默认级别 Trace 测试
    #[test]
    fn test_default_level_is_trace() {
        // GIVEN: 默认 FileAppender
        let temp_dir = TempDir::new().expect("创建临时目录失败");
        let log_path = temp_dir.path().join("default_level.log");

        let appender = FileAppender::new(&log_path).expect("创建 FileAppender 失败");

        // THEN: 默认级别应为 Trace
        assert_eq!(appender.level(), Level::Trace);
    }

    // ========================================
    // 所有日志级别写入测试
    // ========================================

    /// UT-5.1-011: 测试所有日志级别都能写入
    #[test]
    fn test_all_levels_write() {
        // GIVEN: FileAppender
        let temp_dir = TempDir::new().expect("创建临时目录失败");
        let log_path = temp_dir.path().join("all_levels.log");

        let appender = FileAppender::new(&log_path).expect("创建 FileAppender 失败");

        // WHEN: 写入所有级别的日志
        for level in [
            Level::Trace,
            Level::Debug,
            Level::Info,
            Level::Warn,
            Level::Error,
            Level::Fatal,
        ] {
            let event = LogEvent::new(level, "test", format!("{:?} message", level));
            appender.write(&event).expect("写入失败");
        }
        appender.flush().expect("刷新失败");

        // THEN: 所有日志应被写入
        let content = std::fs::read_to_string(&log_path).expect("读取文件失败");
        let lines: Vec<&str> = content.lines().collect();
        assert_eq!(lines.len(), 6, "应有 6 条日志");
    }

    // ========================================
    // Unicode 内容测试
    // ========================================

    /// UT-5.1-012: Unicode 内容测试
    #[test]
    fn test_unicode_content() {
        // GIVEN: FileAppender
        let temp_dir = TempDir::new().expect("创建临时目录失败");
        let log_path = temp_dir.path().join("unicode.log");

        let appender = FileAppender::new(&log_path).expect("创建 FileAppender 失败");
        let event = LogEvent::new(Level::Info, "日志::模块", "消息 🚀 émoji テスト");

        // WHEN: 写入 Unicode 内容
        appender.write(&event).expect("写入失败");
        appender.flush().expect("刷新失败");

        // THEN: Unicode 应正确保存
        let content = std::fs::read_to_string(&log_path).expect("读取文件失败");
        assert!(content.contains("日志::模块"));
        assert!(content.contains("🚀"));
        assert!(content.contains("テスト"));
    }

    // ========================================
    // AC-5.2: 文件路径配置测试 (Story 5-2)
    // ========================================

    /// UT-5.2-001: 显式相对路径测试 - 验证 "logs/app.log" 格式路径
    #[test]
    fn test_explicit_relative_path() {
        // GIVEN: 相对路径格式
        let temp_dir = TempDir::new().expect("创建临时目录失败");
        let relative_path = temp_dir.path().join("logs").join("app.log");

        // WHEN: 创建 FileAppender
        let appender = FileAppender::new(&relative_path).expect("创建 FileAppender 失败");
        let event = LogEvent::new(Level::Info, "test", "relative path test");
        appender.write(&event).expect("写入失败");
        appender.flush().expect("刷新失败");

        // THEN: 路径应正确解析为 PathBuf
        assert_eq!(appender.path(), relative_path.as_path());
        assert!(relative_path.exists(), "文件应被创建");

        let content = std::fs::read_to_string(&relative_path).expect("读取文件失败");
        assert!(content.contains("relative path test"));
    }

    /// UT-5.2-001b: 嵌套相对路径测试 - 验证 "a/b/c/app.log" 格式路径
    #[test]
    fn test_nested_relative_path() {
        // GIVEN: 嵌套相对路径
        let temp_dir = TempDir::new().expect("创建临时目录失败");
        let nested_path = temp_dir
            .path()
            .join("a")
            .join("b")
            .join("c")
            .join("nested.log");

        // WHEN: 创建 FileAppender
        let appender = FileAppender::new(&nested_path).expect("创建 FileAppender 失败");
        let event = LogEvent::new(Level::Debug, "test", "nested path test");
        appender.write(&event).expect("写入失败");
        appender.flush().expect("刷新失败");

        // THEN: 路径应正确解析，目录应被创建
        assert_eq!(appender.path(), nested_path.as_path());
        assert!(nested_path.exists(), "文件应被创建");
        assert!(
            nested_path.parent().expect("应有父目录").exists(),
            "父目录应存在"
        );
    }

    /// UT-5.2-002: 绝对路径测试 - 验证 tempdir 的绝对路径
    #[test]
    fn test_absolute_path() {
        // GIVEN: 绝对路径（tempdir 返回绝对路径）
        let temp_dir = TempDir::new().expect("创建临时目录失败");
        let absolute_path = temp_dir.path().join("absolute.log");

        // 验证是绝对路径
        assert!(absolute_path.is_absolute(), "应为绝对路径");

        // WHEN: 创建 FileAppender
        let appender = FileAppender::new(&absolute_path).expect("创建 FileAppender 失败");
        let event = LogEvent::new(Level::Info, "test", "absolute path test");
        appender.write(&event).expect("写入失败");
        appender.flush().expect("刷新失败");

        // THEN: 路径应正确解析
        assert_eq!(appender.path(), absolute_path.as_path());
        assert!(absolute_path.exists(), "文件应被创建");

        let content = std::fs::read_to_string(&absolute_path).expect("读取文件失败");
        assert!(content.contains("absolute path test"));
    }

    /// UT-5.2-003: 路径解析验证 - 确认 path() 返回与输入一致的路径
    #[test]
    fn test_path_resolution_consistency() {
        // GIVEN: 各种路径格式
        let temp_dir = TempDir::new().expect("创建临时目录失败");

        // 测试简单文件名
        let simple_path = temp_dir.path().join("simple.log");
        let appender1 = FileAppender::new(&simple_path).expect("创建失败");
        assert_eq!(appender1.path(), simple_path.as_path());

        // 测试带目录的路径
        let dir_path = temp_dir.path().join("subdir").join("file.log");
        let appender2 = FileAppender::new(&dir_path).expect("创建失败");
        assert_eq!(appender2.path(), dir_path.as_path());

        // 测试深层嵌套路径
        let deep_path = temp_dir
            .path()
            .join("a")
            .join("b")
            .join("c")
            .join("d")
            .join("deep.log");
        let appender3 = FileAppender::new(&deep_path).expect("创建失败");
        assert_eq!(appender3.path(), deep_path.as_path());
    }

    /// UT-5.2-004: 路径边界情况 - Unicode 路径
    #[test]
    fn test_unicode_path() {
        // GIVEN: Unicode 路径
        let temp_dir = TempDir::new().expect("创建临时目录失败");
        let unicode_path = temp_dir.path().join("日志目录").join("应用.log");

        // WHEN: 创建 FileAppender
        let appender = FileAppender::new(&unicode_path).expect("创建 FileAppender 失败");
        let event = LogEvent::new(Level::Info, "test", "unicode path test");
        appender.write(&event).expect("写入失败");
        appender.flush().expect("刷新失败");

        // THEN: Unicode 路径应正确处理
        assert!(unicode_path.exists(), "Unicode 路径文件应被创建");
        let content = std::fs::read_to_string(&unicode_path).expect("读取文件失败");
        assert!(content.contains("unicode path test"));
    }

    /// UT-5.2-004b: 路径边界情况 - 特殊字符路径
    #[test]
    fn test_special_char_path() {
        // GIVEN: 包含特殊字符的路径（空格、连字符、下划线）
        let temp_dir = TempDir::new().expect("创建临时目录失败");
        let special_path = temp_dir.path().join("log-files_2025").join("app log.log");

        // WHEN: 创建 FileAppender
        let appender = FileAppender::new(&special_path).expect("创建 FileAppender 失败");
        let event = LogEvent::new(Level::Info, "test", "special char path test");
        appender.write(&event).expect("写入失败");
        appender.flush().expect("刷新失败");

        // THEN: 特殊字符路径应正确处理
        assert!(special_path.exists(), "特殊字符路径文件应被创建");
    }

    /// UT-5.2-004c: 路径边界情况 - 当前目录文件
    #[test]
    fn test_current_dir_file() {
        // GIVEN: 临时目录中的简单文件名
        let temp_dir = TempDir::new().expect("创建临时目录失败");
        let simple_file = temp_dir.path().join("current.log");

        // WHEN: 创建 FileAppender
        let appender = FileAppender::new(&simple_file).expect("创建 FileAppender 失败");
        let event = LogEvent::new(Level::Info, "test", "current dir test");
        appender.write(&event).expect("写入失败");
        appender.flush().expect("刷新失败");

        // THEN: 文件应在指定位置创建
        assert!(simple_file.exists());
        assert_eq!(appender.path(), simple_file.as_path());
    }

    /// UT-5.2-005: 验证路径解析在 new() 中完成
    #[test]
    fn test_path_resolved_in_new() {
        // GIVEN: 路径字符串
        let temp_dir = TempDir::new().expect("创建临时目录失败");
        let path_str = temp_dir.path().join("resolved.log");

        // WHEN: 创建 FileAppender
        let appender = FileAppender::new(&path_str).expect("创建 FileAppender 失败");

        // THEN: path() 应立即返回解析后的 PathBuf
        // 不需要额外的解析步骤
        let resolved_path = appender.path();
        assert!(resolved_path.is_absolute() || !resolved_path.to_string_lossy().is_empty());
        assert_eq!(resolved_path, path_str.as_path());
    }

    // ========================================
    // AC-5.4: 级别过滤边界测试 (Story 5-4)
    // ========================================

    /// UT-5.4-005: 所有级别组合过滤测试 - 验证每个级别作为阈值时的过滤行为
    #[test]
    fn test_all_levels_filter_combination() {
        let all_levels = [
            Level::Trace,
            Level::Debug,
            Level::Info,
            Level::Warn,
            Level::Error,
            Level::Fatal,
        ];

        for (threshold_idx, &threshold) in all_levels.iter().enumerate() {
            // GIVEN: 配置特定阈值的 FileAppender
            let temp_dir = TempDir::new().expect("创建临时目录失败");
            let log_path = temp_dir.path().join(format!("filter_{:?}.log", threshold));

            let appender = FileAppender::new(&log_path)
                .expect("创建 FileAppender 失败")
                .with_level(threshold);

            // WHEN: 写入所有级别的日志
            for &level in &all_levels {
                let event = LogEvent::new(level, "test", format!("{:?}", level));
                appender.write(&event).expect("写入失败");
            }
            appender.flush().expect("刷新失败");

            // THEN: 验证过滤行为
            let content = std::fs::read_to_string(&log_path).expect("读取文件失败");
            let lines: Vec<&str> = content.lines().collect();

            // 预期通过的日志数量 = 总级别数 - 阈值索引
            let expected_count = all_levels.len() - threshold_idx;
            assert_eq!(
                lines.len(),
                expected_count,
                "阈值 {:?} 应允许 {} 条日志通过，实际 {}",
                threshold,
                expected_count,
                lines.len()
            );

            // 验证低于阈值的级别被过滤
            for (level_idx, &level) in all_levels.iter().enumerate() {
                let level_str = format!("{:?}", level);
                if level_idx < threshold_idx {
                    assert!(
                        !content.contains(&level_str),
                        "{:?} 应被阈值 {:?} 过滤",
                        level,
                        threshold
                    );
                } else {
                    assert!(
                        content.contains(&level_str),
                        "{:?} 应通过阈值 {:?}",
                        level,
                        threshold
                    );
                }
            }
        }
    }

    /// UT-5.4-006: FATAL 级别过滤测试 - 验证最高级别作为阈值时只允许 FATAL 通过
    #[test]
    fn test_fatal_level_filter() {
        // GIVEN: 配置 FATAL 级别的 FileAppender
        let temp_dir = TempDir::new().expect("创建临时目录失败");
        let log_path = temp_dir.path().join("fatal_filter.log");

        let appender = FileAppender::new(&log_path)
            .expect("创建 FileAppender 失败")
            .with_level(Level::Fatal);

        // WHEN: 写入所有级别的日志
        for level in [
            Level::Trace,
            Level::Debug,
            Level::Info,
            Level::Warn,
            Level::Error,
            Level::Fatal,
        ] {
            let event = LogEvent::new(level, "test", format!("{:?} message", level));
            appender.write(&event).expect("写入失败");
        }
        appender.flush().expect("刷新失败");

        // THEN: 只有 FATAL 级别日志应被写入
        let content = std::fs::read_to_string(&log_path).expect("读取文件失败");
        let lines: Vec<&str> = content.lines().collect();

        assert_eq!(lines.len(), 1, "只应有 1 条 FATAL 日志");
        assert!(content.contains("Fatal message"), "应包含 FATAL 消息");
        assert!(!content.contains("Trace message"), "不应包含 TRACE");
        assert!(!content.contains("Debug message"), "不应包含 DEBUG");
        assert!(!content.contains("Info message"), "不应包含 INFO");
        assert!(!content.contains("Warn message"), "不应包含 WARN");
        assert!(!content.contains("Error message"), "不应包含 ERROR");
    }

    /// UT-5.4-007: with_level() builder 链式调用测试
    #[test]
    fn test_with_level_builder_chain() {
        // GIVEN: FileAppender 使用链式调用配置
        let temp_dir = TempDir::new().expect("创建临时目录失败");
        let log_path = temp_dir.path().join("builder_chain.log");

        // WHEN: 使用链式调用创建 FileAppender
        let appender = FileAppender::new(&log_path)
            .expect("创建 FileAppender 失败")
            .with_level(Level::Error)
            .with_formatter(Box::new(TextFormatter::new()));

        // THEN: 级别应正确设置
        assert_eq!(appender.level(), Level::Error);

        // 验证过滤行为
        let warn_event = LogEvent::new(Level::Warn, "test", "warn");
        let error_event = LogEvent::new(Level::Error, "test", "error");

        appender.write(&warn_event).expect("写入失败");
        appender.write(&error_event).expect("写入失败");
        appender.flush().expect("刷新失败");

        let content = std::fs::read_to_string(&log_path).expect("读取文件失败");
        assert!(!content.contains("warn"), "WARN 应被过滤");
        assert!(content.contains("error"), "ERROR 应通过");
    }

    /// UT-5.4-008: 默认级别允许所有日志通过测试
    #[test]
    fn test_default_level_allows_all() {
        // GIVEN: 默认 FileAppender（不调用 with_level）
        let temp_dir = TempDir::new().expect("创建临时目录失败");
        let log_path = temp_dir.path().join("default_allows_all.log");

        let appender = FileAppender::new(&log_path).expect("创建 FileAppender 失败");

        // 验证默认级别
        assert_eq!(appender.level(), Level::Trace, "默认级别应为 Trace");

        // WHEN: 写入所有级别的日志
        for level in [
            Level::Trace,
            Level::Debug,
            Level::Info,
            Level::Warn,
            Level::Error,
            Level::Fatal,
        ] {
            let event = LogEvent::new(level, "test", format!("{:?}", level));
            appender.write(&event).expect("写入失败");
        }
        appender.flush().expect("刷新失败");

        // THEN: 所有 6 条日志都应被写入
        let content = std::fs::read_to_string(&log_path).expect("读取文件失败");
        let lines: Vec<&str> = content.lines().collect();
        assert_eq!(lines.len(), 6, "默认级别应允许所有 6 条日志通过");
    }

    /// UT-5.4-009: 级别边界情况测试 - 相邻级别过滤
    #[test]
    fn test_level_boundary_cases() {
        // 测试每对相邻级别的边界行为
        let adjacent_pairs = [
            (Level::Trace, Level::Debug),
            (Level::Debug, Level::Info),
            (Level::Info, Level::Warn),
            (Level::Warn, Level::Error),
            (Level::Error, Level::Fatal),
        ];

        for (lower, higher) in adjacent_pairs {
            // GIVEN: 配置 higher 级别的 FileAppender
            let temp_dir = TempDir::new().expect("创建临时目录失败");
            let log_path = temp_dir.path().join(format!("boundary_{:?}.log", higher));

            let appender = FileAppender::new(&log_path)
                .expect("创建 FileAppender 失败")
                .with_level(higher);

            // WHEN: 写入相邻的两个级别
            let lower_event = LogEvent::new(lower, "test", format!("{:?}", lower));
            let higher_event = LogEvent::new(higher, "test", format!("{:?}", higher));

            appender.write(&lower_event).expect("写入失败");
            appender.write(&higher_event).expect("写入失败");
            appender.flush().expect("刷新失败");

            // THEN: lower 被过滤，higher 通过
            let content = std::fs::read_to_string(&log_path).expect("读取文件失败");
            assert!(
                !content.contains(&format!("{:?}", lower)),
                "{:?} 应被阈值 {:?} 过滤",
                lower,
                higher
            );
            assert!(
                content.contains(&format!("{:?}", higher)),
                "{:?} 应通过阈值 {:?}",
                higher,
                higher
            );
        }
    }
}
